import { debugMgr } from "./DebugMgr";
import { errorMgr } from "./ErrorMgr";
import { EventId, eventMgr } from "./EventMgr";
import { MsgCoder, MsgId, MsgToc, MsgTos } from "../cfg/Msg";
import { popupMgr } from "./PopupMgr";
import { Xlsx } from "../cfg/Xlsx";

/**
 * 连接管理
 */
export const connMgr = _ as ConnMgr;
export class ConnMgr {

    private _socket: WebSocket;
    private _gateSocket: WebSocket;
    private _svrSocket: WebSocket;
    private _listeners: { [msgId: number]: (msg?: any) => any }

    init() {
        (connMgr as any) = this;
        this._listeners = {};
    }

    /**
     * 连接gate服务器
     */
    connGate() {
        let socket = this._socket = this._gateSocket = new WebSocket(Xlsx.com.gateHost);
        socket.onopen = () => {
            eventMgr.send(EventId.gateConn, {});
            socket.binaryType = "arraybuffer";
            socket.onmessage = event => this.onData(new Uint8Array(event.data));
            socket.onclose = event => {
                eventMgr.send(EventId.gateDisconn, { event });
            };
            socket.onerror = event => {
                eventMgr.send(EventId.gateDisconn, { event });
            };
        }
        socket.onerror = event => {
            socket.close();
            eventMgr.send(EventId.gateConn, { event });
        }
    }

    /**
     * 断开Gate服务器
     */
    disConnGate() {
        if (this._gateSocket) {
            this._gateSocket.close();
            this._gateSocket = null;
        }
    }

    /**
     * 连接Game服务器
     */
    connSvr(host: string) {
        let socket = this._socket = this._svrSocket = new WebSocket(host);
        socket.onopen = () => {
            eventMgr.send(EventId.svrConn, {});
            socket.binaryType = "arraybuffer";
            socket.onmessage = event => this.onData(new Uint8Array(event.data));
            socket.onclose = event => {
                popupMgr.showFloatText("已断开连接");
                eventMgr.send(EventId.svrDisConn, { event });
                location.host && location.reload();
            };
            socket.onerror = event => {
                eventMgr.send(EventId.svrDisConn, { event });
            };
        }
        socket.onerror = event => {
            socket.close();
            eventMgr.send(EventId.svrConn, { event });
        }
    }

    /**
     * 断开Game服务器
     */
    disConnSvr() {
        if (this._svrSocket) {
            this._svrSocket.close();
            this._svrSocket = null;
            this._socket = this._gateSocket;
        }
    }

    private onData(buf: Uint8Array) {
        let msgId = MsgCoder.decodeMsgId(buf);
        if (this._listeners[msgId]) {
            let data: any;
            try {
                data = MsgCoder.decodeToc(msgId);
            } catch (e: any) {
                errorMgr.error(`解码协议消息${msgId}(${MsgId[msgId]})发生错误: `, e);
                return;
            }
            debugMgr.logOnMsg(msgId, data);
            this._listeners[msgId](data);
        }
    }

    /**
     * 监听协议,重复监听会抛出错误
     * @param msgId 
     * @param callback 
     * @param caller 
     */
    on<ID extends Exclude<MsgId, keyof MsgToc>>(id: ID, callback: () => void, caller?: any): void
    on<ID extends keyof MsgToc>(id: ID, callback: (msg?: MsgToc[ID]) => void, caller?: any): void
    on<ID extends MsgId>(msgId: ID, callback: (msg?: any) => void, caller?: any) {
        if (this._listeners[msgId]) throw new Error("重复监听协议: " + msgId);
        this._listeners[msgId] = caller ? callback.bind(caller) : callback;
    }

    /**
     * 发送事件
     * @param id 
     * @param msg 
     */
    send<ID extends Exclude<MsgId, keyof MsgTos>>(id: ID): void
    send<ID extends keyof MsgTos>(id: ID, msg: MsgTos[ID]): void
    send(id: MsgId, msg?: any) {
        debugMgr.logSendMsg(id, msg);
        MsgCoder.encodeMsgId(id);
        this._socket.send(MsgCoder.encodeTos(id, msg));
    }

}

declare global {
    interface EventData {
        [EventId.gateConn]: { event?: Event }
        [EventId.gateDisconn]: { event?: Event }
        [EventId.svrConn]: { event?: Event }
        [EventId.svrDisConn]: { event?: Event }
    }
}